import gleam/io.{println}

// gleam has reimport error, don't import lib again
import gleam/bool
import gleam/bytes_builder
import gleam/float
import gleam/int
import gleam/string as text
import gleam/string_builder.{type StringBuilder}

pub fn print_names() {
  println("hello mike")
  io.println(text.reverse("hello joe"))
}

pub fn debug_print(x: any) {
  io.debug(x)
}

fn double(a: Int) -> Int {
  multiply(a, 2)
}

fn multiply(a: Int, b: Int) -> Int {
  a * b
}

// test func
type UserId =
  Int

const ints: List(Int) = [1, 2, 3]

const floats: List(Float) = [1.0, 2.0, 99.0]

pub fn stage1_test() -> Int {
  debug_print(1 + 1)
  debug_print(1_230_000)
  debug_print(1 == 1)
  debug_print(1 != 1)
  debug_print(1 / 1)
  print_names()
  debug_print("hello debug")
  debug_print(int.max(11, 22))
  debug_print(int.clamp(5, 10, 20))

  debug_print(float.max(2.0, 9.5))
  debug_print(float.ceiling(5.4))

  let eql: Bool = 100 == 100
  debug_print(eql)
  io.debug(bool.to_string(True))
  io.debug(bool.to_int(True))

  io.debug(text.append("abc", "def"))

  let x = "Original"
  io.debug(x)
  let y = x
  io.debug(y)

  let x = "New"
  // x is reassign as new value
  io.debug(x)

  io.debug(y)
  // y still ref to original x

  let _discard_var = 100_100_100

  let _bytes: bytes_builder.BytesBuilder = bytes_builder.new()

  let _text: StringBuilder = string_builder.new()

  // Alias
  let the_user: UserId = 1
  let other_user: Int = 1
  io.debug(the_user == other_user)
  // alias, not type unreplaceable

  // Block
  let fahrenheit = {
    let degress = 64
    degress
  }

  let celsius = { fahrenheit - 32 } * 5 / 9

  io.debug(celsius)

  // List
  let ints = [1, 2, 3]
  io.debug(ints)
  io.debug([-1, 0, ..ints])
  // prepend with -1 0

  let strs: List(String) = ["fucker fucker", "etcix", "nidielaila"]
  io.debug(strs)

  // Constants

  io.debug(ints)
  io.debug(floats)
  // Function using
  io.debug(double(111))
  io.debug(multiply(11, 11))

  // Higher order functions
  io.debug(apply_fn_twice_to(1, add_one))
  let my_add = add_one
  io.debug(apply_fn_twice_to(1, my_add))

  // Anoymous functions
  let plus_one = fn(a: Int) { a + 1 }
  let holy_shit_func = fn(a: Int) {
    let tmp_func = fn(a) { a }
    // take a, return a
    tmp_func(a)
    tmp_func
  }
  io.debug(apply_fn_twice_to(1, plus_one))

  io.debug(holy_shit_func(1))
  // print func signature
  io.debug(holy_shit_func(1)(1))
  // consume the func (Int) -> Int

  1
}

fn apply_fn_twice_to(a: Int, passed_func: fn(Int) -> Int) -> Int {
  passed_func(passed_func(a))
}

fn add_one(a: Int) -> Int {
  a + 1
}
